package ddz.db.dao;

import com.kaka.notice.Proxy;
import ddz.db.entity.RankInfo;
import ddz.db.entity.UserInfo;
import ddz.db.redis.JedisFactory;
import ddz.utils.Page;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Tuple;

import java.util.*;

public class RankDao extends Proxy {

    /**
     * 从缓存中获取排行列表
     *
     * @param key
     * @param page
     * @return
     */
    protected List<RankInfo> getRankListFromRedis(String key, Page page) {
        Set<Tuple> resultSet = null;
        try (Jedis jedis = JedisFactory.getFactory().getJedis()) {
            if (jedis.exists(key)) {
                resultSet = jedis.zrevrangeWithScores(key, 0, 100); //获取排行数据
            }
        }
        List<RankInfo> list;
        if (resultSet != null && !resultSet.isEmpty()) {
            List<Tuple> resultList = new ArrayList<>(resultSet);
            Map<Long, Integer> rankMap = new HashMap<>(resultList.size());
            for (int i = 0; i < resultList.size(); i++) { //由于上面获取了最多100条数据，故此处直接以uid和rank对应
                Tuple tuple = resultList.get(i);
                Long uid = Long.parseLong(tuple.getElement());
                rankMap.put(uid, (i + 1));
            }
            if (page != null) { //如果需要翻页，则截取本页对应的排行数据
                page.setTotals(resultSet.size());
                int start = page.getStart();
                resultList = resultList.subList(start, start + page.getNum());
            }
            list = new ArrayList<>(resultList.size());
            for (Tuple tuple : resultList) {
                Long uid = Long.parseLong(tuple.getElement());
                double score = tuple.getScore();
                RankInfo rankInfo = new RankInfo();
                rankInfo.setUid(uid);
                rankInfo.setScore((float) score);
                rankInfo.setRank(rankMap.get(rankInfo.getUid()));
                list.add(rankInfo);
            }
        } else {
            list = new ArrayList<>(0);
        }
        return list;
    }

    protected void bindUserInfo(List<RankInfo> list, UserDao userDao) {
        if (list == null || list.isEmpty()) return;
        Set<Long> uidSet = new HashSet<>(list.size());
        for (RankInfo rankInfo : list) {
            uidSet.add(rankInfo.getUid());
        }
        Map<Long, UserInfo> userInfoMap = userDao.getUserInfoMap(uidSet, "uid", "nickname", "headImg");
        int i = 0, max = list.size();
        while (i < max) {
            RankInfo rankInfo = list.get(i);
            UserInfo userInfo = userInfoMap.get(rankInfo.getUid());
            if (userInfo == null) {
                list.remove(i);
                max--;
                continue;
            }
            rankInfo.setNickname(userInfo.getNickname());
            rankInfo.setHeadImg(userInfo.getHeadImg());
            i++;
        }
    }

    protected RankInfo bindUserInfo(RankInfo rankInfo, UserDao userDao) {
        if (rankInfo == null) return null;
        UserInfo userInfo = userDao.getUserInfo(rankInfo.getUid(), "uid", "nickname", "headImg");
        if (userInfo == null) return null;
        rankInfo.setHeadImg(userInfo.getHeadImg());
        rankInfo.setNickname(userInfo.getNickname());
        return rankInfo;
    }

    /**
     * 获取指定用户的排行数据
     *
     * @param key
     * @param uid
     * @return
     */
    protected RankInfo getUserRankInfoByUid(String key, long uid) {
        List<Object> result;
        String member = String.valueOf(uid);
        try (Jedis jedis = JedisFactory.getFactory().getJedis()) {
            Pipeline pipeline = jedis.pipelined();
            pipeline.zrevrank(key, member);
            pipeline.zscore(key, member);
            result = pipeline.syncAndReturnAll();
        }
        if (result != null && !result.isEmpty()) {
            if (result.get(0) != null) {
                Long rank = (Long) result.get(0);
                Double score = (Double) result.get(1);
                RankInfo rankInfo = new RankInfo();
                rankInfo.setUid(uid);
                if (rank != null) {
                    rankInfo.setRank((int) (long) rank + 1);
                } else {
                    rankInfo.setRank(-1);
                }
                if (score != null) rankInfo.setScore((float) (double) score);
                return rankInfo;
            }
        }
        return null;
    }

}
